package psim;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.XMLReader;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Trida, ktera prostrednictvim statickych metod implementuje
 * XML SAX parser a serializer. 
 * @author Tomas Drimal
 */
public class FileAccess extends DefaultHandler {

    int s = 500;
    private String[] StrNums;
    private StringBuffer buff = new StringBuffer();

    /**
     * metoda ktera nacte xml soubor s casticemi
     * @param name jmeno souboru
     */
    public static void LoadFromFile(String name) {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setValidating(false);

            SAXParser parser = factory.newSAXParser();

            XMLReader reader = parser.getXMLReader();

            FileAccess test = new FileAccess();
            reader.setContentHandler(test);
            reader.setErrorHandler(test);
            reader.parse(name);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }

    /**
     * Obsluzna metoda, je volana vzdy, kdyz
     * parser narazi na zacatek XML elementu
     * @param uri
     * @param localName
     * @param qName
     * @param atts
     * @throws SAXException
     */
    @Override
    public void startElement(String uri, String localName,
            String qName, Attributes atts) throws SAXException {

        if (qName.equalsIgnoreCase("dt")) {
            s = 0;
        }
        if (qName.equalsIgnoreCase("scale_x")) {
            s = 1;
        }
        if (qName.equalsIgnoreCase("scale_y")) {
            s = 2;
        }
        if (qName.equalsIgnoreCase("bound")) {
            s = 3;
        }
        if (qName.equalsIgnoreCase("ptc")) {
            s = 4;
        }
    }

    /**
     * Obsluzna metoda parseru, je volana vzdy,
     * kdyz parser narazi na konec XML elementu
     * @param uri
     * @param localName
     * @param qName
     * @throws SAXException
     */
    @Override
    public void endElement(String uri, String localName,
            String qName) throws SAXException {
        switch (s) {
            case 0:
                Main.dt = Double.valueOf(buff.toString());
            case 1:
                Main.scale_x = Double.valueOf(buff.toString());
                break;
            case 2:
                Main.scale_y = Double.valueOf(buff.toString());
                break;
            case 3:
                Main.bound = Boolean.parseBoolean(buff.toString());
                break;
            case 4:
                StrNums = buff.toString().split("[ ]");
                double x = Double.valueOf(StrNums[0]); //x-ova poloha
                double y = Double.valueOf(StrNums[1]); //y-nova poloha
                double vx = Double.valueOf(StrNums[2]); //rychlost ve smeru osy x
                double vy = Double.valueOf(StrNums[3]); //rychlost ve smeru osy y
                double m = Double.valueOf(StrNums[4]); //hmotnost castice
                double q = Double.valueOf(StrNums[5]); //naboj castice
                double d = Double.valueOf(StrNums[6]); //prumer castice
                short col = Short.valueOf(StrNums[7]); //barva castice

                Main.particles.add(new Particle(x, y, vx, vy, m, q, d, col));
                break;
            default:
        }
        s = 500;
        buff.delete(0, buff.length());
    }

    /**
     * Metoda, ktera je volana nad znaky, ktere jsou mezi 
     * elementy XML dokumentu - do bufferu uklada znaky,
     * ktere se nachazi mezi temito elementy
     * @param ch
     * @param start
     * @param length
     * @throws SAXException
     */
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        buff.append(new String(ch, start, length));
    }

    @Override
    public void error(SAXParseException e) {
        System.out.println(e.getMessage());
    }

    @Override
    public void warning(SAXParseException e) {
        System.out.println(e.getMessage());
    }

    @Override
    public void fatalError(SAXParseException e) {
        System.out.println(e.getMessage());
    }

    public static void SaveToFile(String filename) throws FileNotFoundException, IOException, SAXException {
        FileOutputStream fos = new FileOutputStream(filename);
// XERCES 1 or 2 additionnal classes.
        OutputFormat of = new OutputFormat("XML", "UTF-8", false);
        XMLSerializer serializer = new XMLSerializer(fos, of);
// SAX2.0 ContentHandler.
        ContentHandler hd = serializer.asContentHandler();
        hd.startDocument();
// ptcs attributes - vpodstate atributy vsech elementu
        AttributesImpl atts = new AttributesImpl();
// ptcs tag.
        hd.startElement("", "", "ptcs", atts);
// dt tag.
        hd.startElement("", "", "dt", atts);
        hd.characters(toChArr(Main.dt), 0, toChArr(Main.dt).length);
        hd.endElement("", "", "dt");
// scale_x tag.
        hd.startElement("", "", "scale_x", atts);
        hd.characters(toChArr(Main.scale_x), 0, toChArr(Main.scale_x).length);
        hd.endElement("", "", "scale_x");
// scale_y tag.
        hd.startElement("", "", "scale_y", atts);
        hd.characters(toChArr(Main.scale_y), 0, toChArr(Main.scale_y).length);
        hd.endElement("", "", "scale_x");
// bound tag.
        hd.startElement("", "", "bound", atts);
        hd.characters(Boolean.toString(Main.bound).toCharArray(), 0,
                Boolean.toString(Main.bound).length());
        hd.endElement("", "", "bound");
// ptc tags.
        String ptc = new String();
        for (int i = 0; i < Main.particles.size(); i++) {
            hd.startElement("", "", "ptc", atts);
            ptc = Main.particles.get(i).tString();
            hd.characters(ptc.toCharArray(), 0, ptc.length());
            hd.endElement("", "", "ptc");
        }
        hd.endElement("", "", "ptcs");
        hd.endDocument();
        fos.close();
    }

    private static char[] toChArr(double nr) {
        return Double.toString(nr).toCharArray();
    }

    public static void SaveToCSV(File file, ArrayList<String> buff)
            throws FileNotFoundException, IOException {
        if (file == null) {
            throw new IllegalArgumentException("File should not be null.");
        }
        if (!file.exists()) {
            throw new FileNotFoundException("File does not exist: " + file);
        }
        if (!file.isFile()) {
            throw new IllegalArgumentException(
                    "Should not be a directory: " + file);
        }
        if (!file.canWrite()) {
            throw new IllegalArgumentException(
                    "File cannot be written: " + file);
        }

        //use buffering
        Writer output = new BufferedWriter(new FileWriter(file));
        try {
            //FileWriter always assumes default encoding is OK!
            for (int i = 0; i < buff.size(); i++) {
                output.write(buff.get(i)+"\n");
            }
        } finally {
            output.close();
        }
    }
}


